home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Magnum One
/
Magnum One (Mid-American Digital) (Disc Manufacturing).iso
/
d12
/
v9n04.arc
/
CARDS.PAS
< prev
next >
Wrap
Pascal/Delphi Source File
|
1990-01-30
|
19KB
|
670 lines
UNIT Cards;
(**********************)
(**) INTERFACE (**)
(**********************)
USES crt, ListObj;
CONST pips : array[0..12] of char = 'A23456789TJQK';
suits : array[0..3] of char = (#3, #4, #5, #6);
TYPE
CardP = ^Card;
LCardP = ^LCard;
PileP = ^Pile;
DeckP = ^Deck;
LDeckP = ^LDeck;
HandP = ^Hand;
PlayerP = ^Player;
direction = (up, dn, lt, rt);
decision = (no, yes, maybe);
CARD = OBJECT (Node)
value, X, Y : Word;
HoldAttr, TableColor,
PipColor : Byte;
FaceUp : Boolean;
CONSTRUCTOR Init(iValue : Word; iTC : Byte; iFaceUp : boolean);
CONSTRUCTOR InitXY(iValue, iX, iY : word;
iTC : Byte; iFaceUp : boolean);
DESTRUCTOR done; virtual;
{--- next 4 routines locate card at (X, Y) ---}
PROCEDURE DrawAt(vX, vY : Word); virtual;
PROCEDURE HideAt(vX, vY : Word); virtual;
PROCEDURE PointTo(vX, vY : Word; direc : direction); virtual;
PROCEDURE UnPoint(vX, vY : Word; direc : direction); virtual;
{--- next 4 routines use card's intrinsic location ---}
PROCEDURE Display;
PROCEDURE hide;
PROCEDURE PointT(direc : direction);
PROCEDURE UnPoin(direc : direction);
FUNCTION GetRank : Byte; virtual;
FUNCTION GetSuit : Byte; virtual;
{--- remaining routines are static ---}
PROCEDURE TurnUp;
PROCEDURE TurnDown;
PROCEDURE PutInPlace(iX, iY : Word);
FUNCTION GetValue : Word;
END;
LCard = OBJECT (Card)
{--- Little Card -- differs only in how it's displayed ---}
CONSTRUCTOR Init(iValue : Word; iTC : Byte; iFaceUP : boolean);
CONSTRUCTOR InitXY(iValue, iX, iY : word;
iTC : Byte; iFaceUp : boolean);
DESTRUCTOR Done; virtual;
PROCEDURE DrawAt(vX, vY : Word); virtual;
PROCEDURE HideAt(vX, vY : Word); virtual;
END;
Pile = OBJECT (Node)
{--- a "smart" list of cards ---}
X, Y, NumInPile : Word;
FaceUp : Decision;
Cards : List;
CONSTRUCTOR Init(iX, iY : Word; iShow : Decision);
DESTRUCTOR Done; virtual;
PROCEDURE AddCard(C : CardP);
PROCEDURE Display; virtual;
PROCEDURE Hide; virtual;
PROCEDURE Sort(bySuit : boolean); virtual;
{--- remaining methods are static ---}
PROCEDURE PlaceAt(iX, iY : Word);
FUNCTION OnTop : CardP;
FUNCTION OnBot : CardP;
FUNCTION FromTop : CardP;
FUNCTION FromBot : CardP;
FUNCTION NextCard(C : CardP) : CardP;
FUNCTION PrevCard(C : CardP) : CardP;
PROCEDURE Remove(C : CardP);
FUNCTION Empty : boolean;
FUNCTION GetX : Word;
FUNCTION GetY : Word;
PROCEDURE TurnUp;
PROCEDURE TurnDown;
FUNCTION GetUp : decision;
END;
Hand = OBJECT (pile)
{--- a hand is a pile with the cards spread out ---}
pX, pY : Byte; {used in pointing to cards}
direc : direction;
CONSTRUCTOR Init(iX, iY : Word; iShow : decision;
iDire : direction);
DESTRUCTOR Done; virtual;
PROCEDURE Display; virtual;
PROCEDURE Hide; virtual;
PROCEDURE PointToCard(CP : CardP; dr : direction); virtual;
PROCEDURE UnPointCard(CP : CardP; dr : direction); virtual;
{--- remaining method is "private" ---}
PROCEDURE Private_Go;
END;
DECK = OBJECT (pile)
{--- a DECK is a PILE that can shuffle ---}
CONSTRUCTOR Init(iX, iY : Word; iTC : Byte);
DESTRUCTOR done; virtual;
PROCEDURE shuffle; virtual;
PROCEDURE AddToBottom(C : CardP);
END;
LDeck = OBJECT (deck)
{--- a LDECK is a DECK of little cards ---}
CONSTRUCTOR Init(iX, iY : Word; iTC : Byte);
DESTRUCTOR done; virtual;
END;
Player = OBJECT (node)
{--- abstract -- each GAME needs a new player type ---}
H : HandP;
name : String;
CONSTRUCTOR Init(iX, iY : Word; iShow : decision;
iDire : direction; iName : String);
DESTRUCTOR Done; virtual;
PROCEDURE TakeCard(C : CardP); virtual;
PROCEDURE ShowHand; virtual;
PROCEDURE PointToMe; virtual;
PROCEDURE UnPointMe; virtual;
{--- remaining methods are static ---}
FUNCTION GetName : String;
FUNCTION OutOfCards : Boolean;
FUNCTION NextNotSelf(L : list; X : PlayerP) : PlayerP;
FUNCTION PrevNotSelf(L : list; X : PlayerP) : PlayerP;
FUNCTION FirsNotSelf(L : List) : PlayerP;
END;
Game = OBJECT
{--- abstract object -- every game will differ ---}
D : deckP;
TableColor : Byte;
players : list;
whoseturn : PlayerP;
CONSTRUCTOR Init(iTC : byte);
DESTRUCTOR done; virtual;
PROCEDURE DealCards(num : word); virtual;
PROCEDURE Display; virtual;
{--- remaining methods are static ---}
PROCEDURE AddPlayer(PP : PlayerP);
END;
(*-non-method routines-------*)
PROCEDURE Frame(x1, y1, x2, y2 : byte; {corner coords}
typ : byte; {type of frame}
clr : boolean; {clear inside?}
clrch : char); {clear with what}
PROCEDURE beep;
PROCEDURE click;
PROCEDURE sad;
PROCEDURE happy;
PROCEDURE fanfare;
(**********************)
(**) IMPLEMENTATION (**)
(**********************)
(*-non-method routines-------*)
PROCEDURE Frame(x1, y1, x2, y2 : byte; {corner coords}
typ : byte; {type of frame}
clr : boolean; {clear inside?}
clrch : char); {clear with what}
TYPE fchars = (ulc, top, urc, side, lrc, llc);
CONST fc : ARRAY[0..2] OF ARRAY[fchars] OF CHAR =
(' ', #218#196#191#179#217#192,
#201#205#187#186#188#200);
VAR
ro, co : Byte;
S : String[80];
BEGIN
FillChar(S, SizeOf(S), fc[typ][top]);
S[0] := char(pred(x2-x1));
GotoXY(x1, y1);
Write(fc[typ][ulc], S, fc[typ][urc]);
GotoXY(x1, y2);
Write(fc[typ][llc], S, fc[typ][lrc]);
FillChar(S[1], pred(SizeOf(S)), clrch);
FOR ro := succ(y1) TO pred(y2) DO
IF clr THEN
BEGIN
GotoXY(x1, ro);
Write(fc[typ][side], S, fc[typ][side])
END
ELSE
BEGIN
GotoXY(x1, ro); Write(fc[typ][side]);
GotoXY(x2, ro); Write(fc[typ][side]);
END;
END;
PROCEDURE SoundDel(S, D : Word); BEGIN Sound(S); Delay(D); END;
PROCEDURE beep; BEGIN SoundDel(3000, 100); nosound; END;
PROCEDURE click; BEGIN SoundDel(4000, 10); NoSound; END;
PROCEDURE sad;
VAR N : Byte;
BEGIN
FOR N := 50 DOWNTO 1 DO SoundDel(500+20*N, 5); NoSound;
END;
PROCEDURE happy;
VAR N : Byte;
BEGIN
FOR N := 1 TO 50 DO SoundDel(500+30*N, 5); NoSound;
END;
PROCEDURE fanfare;
BEGIN
SoundDel(523, 200); SoundDel(698, 200);
SoundDel(880, 200); SoundDel(1047, 200);
NoSound; Delay(200);
SoundDel(880, 200); SoundDel(1047, 600);
NoSound;
END;
(*-methods for CARD----------*)
CONSTRUCTOR Card.Init(iValue : Word; iTC : Byte; iFaceUp : boolean);
BEGIN
value := iValue; TableColor := iTC;
IF value < 26 THEN PipColor := LightRed ELSE PipColor := black;
FaceUp := iFaceUp; X := 0; Y := 0;
END;
CONSTRUCTOR Card.InitXY(iValue, iX, iY : word;
iTC : Byte; iFaceUp : boolean);
BEGIN Init(iValue, iTC, iFaceUp); X := iX; Y := iY; END;
DESTRUCTOR card.done; BEGIN END;
PROCEDURE Card.DrawAt(vX, vY : Word);
BEGIN
HoldAttr := TextAttr;
TextBackground(white);
IF FaceUP THEN
BEGIN
TextColor(PipColor);
frame(vX, vY, vX+4, vY+4, 1, true, ' ');
{Write pips across AND down, so card values
will be visible when spread horz. or vert.}
GotoXY(vX+1, vY+2); Write(pips[GetRank]);
GotoXY(vx+2, vY+1); Write(pips[GetRank]);
GotoXY(vX+1, vY+3); Write(suits[GetSuit]);
GotoXY(vX+3, vY+1); Write(suits[GetSuit]);
END
ELSE
BEGIN
TextBackground(blue); TextColor(lightgray);
frame(vX, vY, vX+4, vY+4, 2, true, #176);
END;
TextAttr := HoldAttr;
END;
PROCEDURE Card.HideAt(vX, vY : Word);
BEGIN
HoldAttr := TextAttr;
TextAttr := TableColor;
frame(vX, vY, vX+4, vY+4, 0, true, ' ');
TextAttr := HoldAttr;
END;
PROCEDURE Card.PointTo(vX, vY : Word; direc : direction);
BEGIN
HoldAttr := TextAttr;
TextAttr := TableColor;
CASE direc OF
up : BEGIN; GotoXY(vX+1, vY-1); Write(#25); END;
dn : BEGIN; GotoXY(vX+1, vY+5); Write(#24); END;
lt : BEGIN; GotoXY(vX-1, vY+2); Write(#26); END;
rt : BEGIN; GotoXY(vX+5, vY+2); Write(#27); END;
END;
TextAttr := HoldAttr;
END;
PROCEDURE Card.UnPoint(vX, vY : Word; direc : direction);
BEGIN
HoldAttr := TextAttr;
TextAttr := TableColor;
CASE direc OF
up : BEGIN; GotoXY(vX+1, vY-1); Write(' '); END;
dn : BEGIN; GotoXY(vX+1, vY+5); Write(' '); END;
lt : BEGIN; GotoXY(vX-1, vY+2); Write(' '); END;
rt : BEGIN; GotoXY(vX+5, vY+2); Write(' '); END;
END;
TextAttr := HoldAttr;
END;
PROCEDURE Card.Display; BEGIN DrawAt(X, Y); END;
PROCEDURE Card.Hide; BEGIN HideAt(X, Y); END;
PROCEDURE Card.PointT(direc : direction);
BEGIN PointTo(X, Y, direc); END;
PROCEDURE Card.Unpoin(direc : direction);
BEGIN UnPoint(X, Y, direc); END;
FUNCTION Card.GetRank : Byte; BEGIN GetRank := value MOD 13; END;
FUNCTION Card.GetSuit : Byte; BEGIN GetSuit := value DIV 13; END;
PROCEDURE Card.TurnUp; BEGIN FaceUp := True; END;
PROCEDURE Card.TurnDown; BEGIN FaceUp := False; END;
PROCEDURE Card.PutInPlace(iX, iY : Word);
BEGIN X := iX; Y := iY; END;
FUNCTION Card.GetValue : Word; BEGIN GetValue := Value; END;
(*-methods for LCard---------*)
CONSTRUCTOR LCard.Init(iValue : Word;
iTC : Byte; iFaceUP : boolean);
BEGIN Card.Init(iValue, iTC, iFaceUp); END;
CONSTRUCTOR LCard.InitXY(iValue, iX, iY : word;
iTC : Byte; iFaceUp : boolean);
BEGIN Init(iValue, iTC, iFaceUp); X := iX; Y := iY; END;
DESTRUCTOR LCard.Done; BEGIN Card.Done; END;
PROCEDURE LCard.DrawAt(vX, vY : Word);
BEGIN
HoldAttr := TextAttr;
TextBackground(White);
IF FaceUp THEN
BEGIN
TextColor(PipColor);
GotoXY(vX, vY); Write(' ',pips[GetRank],' ');
GotoXY(vX, succ(vY)); Write(' ',suits[GetSuit],' ');
END
ELSE
BEGIN
TextColor(blue);
GotoXY(vX, vY); Write(#176#176#176);
GotoXY(vX, succ(vY)); Write(#176#176#176);
END;
TextAttr := HoldAttr;
END;
PROCEDURE LCard.HideAt(vX, vY : Word);
BEGIN
HoldAttr := TextAttr;
TextAttr := TableColor;
GotoXY(vX, vY); Write(' ');
GotoXY(vX, succ(vY)); Write(' ');
TextAttr := HoldAttr;
END;
(*-methods for PILE----------*)
CONSTRUCTOR Pile.Init(iX, iY : Word; iShow : decision);
BEGIN
X := iX; Y := iY; Cards.Init; NumInPile := 0; FaceUp := iShow;
END;
DESTRUCTOR Pile.Done;
BEGIN Cards.Done; END;
PROCEDURE Pile.AddCard(C : CardP);
BEGIN
IF FaceUp = yes THEN C^.TurnUp;
IF FaceUP = no THEN C^.TurnDown;
Cards.Append(C); Inc(NumInPile);
END;
PROCEDURE Pile.Display;
BEGIN IF NOT cards.Empty THEN CardP(cards.last)^.DrawAt(X, Y); END;
PROCEDURE Pile.Hide;
BEGIN IF NOT cards.Empty THEN CardP(cards.last)^.HideAt(X, Y); END;
PROCEDURE Pile.Sort(bySuit : boolean);
VAR
N, M, T : CardP;
FUNCTION greater(xM, xN : CardP) : Boolean;
VAR Sm, Sn, Rm, Rn : Byte;
BEGIN
Sm := xM^.GetSuit;
Sn := xN^.GetSuit;
Rm := xM^.GetRank;
Rn := xN^.GetRank;
greater := false;
IF BySuit THEN
BEGIN
IF Sm>Sn THEN greater := true
ELSE IF (Sm = Sn) AND (Rm>Rn) THEN greater := true;
END
ELSE
BEGIN
IF Rm > Rn THEN greater := true
ELSE IF (Rm = Rn) AND (Sm>Sn) THEN greater := true;
END;
END;
BEGIN {immediate exchange selection sort}
N := OnTop;
WHILE N <> OnBot DO
BEGIN
M := OnBot;
WHILE M <> N DO
BEGIN
IF Greater(M, N) THEN
BEGIN
Cards.SwapInList(M, N);
T := M; M := N; N := T;
END;
M := NextCard(M);
END;
N := PrevCard(N);
END;
END;
PROCEDURE Pile.PlaceAt(iX, iY : Word); BEGIN X := iX; Y := iY; END;
FUNCTION Pile.OnTop : CardP; BEGIN OnTop := CardP(Cards.Last); END;
FUNCTION Pile.OnBot : CardP; BEGIN OnBot := CardP(Cards.Firs); END;
FUNCTION Pile.FromTop : CardP;
BEGIN
IF (NumInPile = 1) AND (X+Y>0) THEN
CardP(Cards.Last)^.HideAt(X, Y);
FromTop := CardP(Cards.Last);
Cards.remove(Cards.Last); Dec(NumInPile);
END;
FUNCTION Pile.FromBot : CardP;
BEGIN
IF (NumInPile = 1) AND (X+Y>0) THEN
CardP(Cards.Last)^.HideAt(X, Y);
FromBot := CardP(Cards.Firs);
Cards.Remove(Cards.Firs); Dec(NumInPile);
END;
FUNCTION Pile.GetX : Word; BEGIN GetX := X; END;
FUNCTION Pile.GetY : Word; BEGIN GetY := Y; END;
FUNCTION Pile.Empty : boolean; BEGIN Empty := cards.empty; END;
FUNCTION Pile.NextCard(C : CardP) : CardP;
BEGIN NextCard := CardP(cards.Next(C)); END;
FUNCTION Pile.PrevCard(C : CardP) : CardP;
BEGIN PrevCard := CardP(cards.Prev(C)); END;
PROCEDURE Pile.Remove(C : CardP);
BEGIN
IF (NumInPile = 1) AND (X+Y>0) THEN
CardP(Cards.Last)^.HideAt(X, Y);
cards.remove(C); Dec(NumInPile);
END;
PROCEDURE Pile.TurnUp; BEGIN FaceUp := yes; END;
PROCEDURE Pile.TurnDown; BEGIN FaceUp := no; END;
FUNCTION Pile.GetUp : decision; BEGIN GetUp := FaceUp; END;
(*-methods for HAND----------*)
CONSTRUCTOR hand.Init(iX, iY : Word; iShow : decision;
iDire : direction);
BEGIN Pile.Init(iX, iY, iShow); direc := iDire; END;
DESTRUCTOR Hand.Done; BEGIN Pile.done; END;
PROCEDURE Hand.Private_Go;
BEGIN
CASE direc OF
up : Dec(pY, 2);
dn : Inc(pY, 2);
lt : Dec(pX, 2);
rt : Inc(pX, 2);
END;
END;
PROCEDURE Hand.Display;
VAR C : CardP;
BEGIN
pX := X; pY := Y; C := CardP(cards.Firs);
WHILE C <> NIL DO
BEGIN
C^.DrawAt(pX, pY); Private_Go;
C := CardP(cards.next(C));
END;
END;
PROCEDURE Hand.Hide;
VAR C : CardP;
BEGIN
pX := X; pY := Y; C := CardP(cards.Firs);
WHILE C <> NIL DO
BEGIN
C^.HideAt(pX, pY); Private_Go;
C := CardP(cards.next(C));
END;
END;
PROCEDURE Hand.PointToCard(CP : CardP; dr : direction);
VAR C : CardP;
BEGIN
pX := X; pY := Y; C := CardP(cards.Firs);
WHILE (C<>NIL) AND (C<>CP) DO
BEGIN
C := CardP(cards.next(C)); Private_Go;
END;
IF C <> NIL THEN C^.PointTo(pX, pY, dr);
END;
PROCEDURE Hand.UnPointCard(CP : CardP; dr : direction);
VAR C : CardP;
BEGIN
pX := X; pY := Y; C := CardP(cards.Firs);
WHILE (C<>NIL) AND (C<>CP) DO
BEGIN
C := CardP(cards.next(C)); Private_Go;
END;
IF C <> NIL THEN C^.UnPoint(pX, pY, dr);
END;
(*-methods for DECK----------*)
CONSTRUCTOR deck.Init(iX, iY : Word; iTC : Byte);
VAR valu : word;
BEGIN
Pile.Init(iX, iY, no);
FOR valu := 0 to 51 DO
AddCard(New(CardP, Init(valu, iTC, false)));
END;
DESTRUCTOR Deck.done; BEGIN Pile.Done; END;
PROCEDURE Deck.Shuffle;
VAR N,M,T:CardP;
BEGIN
N := OnBot;
WHILE N <> NIL DO
BEGIN
M := CardP(Cards.Nth(succ(random(NumInPile))));
Cards.SwapInList(N, M);
T := M; M := N; N := T;
N := NextCard(N);
END;
END;
PROCEDURE Deck.AddToBottom(C : CardP);
BEGIN
IF FaceUp = yes THEN C^.TurnUp;
IF FaceUP = no THEN C^.TurnDown;
Cards.Insert(cards.Firs, C);
Inc(NumInPile);
END;
(*-methods for LDECK---------*)
CONSTRUCTOR LDeck.Init(iX, iY : Word; iTC : Byte);
VAR valu : Word;
BEGIN
Pile.Init(iX, iY, no);
FOR valu := 0 to 51 DO
AddCard(New(LCardP, Init(valu, iTC, false)));
END;
DESTRUCTOR LDeck.done; BEGIN Deck.Done; END;
(*-methods for Player--------*)
CONSTRUCTOR Player.Init(iX, iY : Word; iShow : decision;
iDire : direction; iName : String);
BEGIN New(H, Init(iX, iY, iShow, iDire)); name := iName; END;
DESTRUCTOR Player.Done; BEGIN dispose(H, done); END;
PROCEDURE Player.TakeCard(C : CardP); BEGIN H^.AddCard(C); END;
FUNCTION Player.GetName : String; BEGIN GetName := name; END;
{--- abstract methods ---}
PROCEDURE Player.ShowHand; BEGIN END;
PROCEDURE Player.PointToMe; BEGIN END;
PROCEDURE Player.UnPointMe; BEGIN END;
FUNCTION Player.OutOfCards : Boolean;
BEGIN OutOfCards := H^.empty; END;
FUNCTION Player.NextNotSelf(L : List; X : PlayerP) : PlayerP;
VAR P : PlayerP;
BEGIN
P := PlayerP(L.NextCirc(X));
IF P = @Self THEN P := PlayerP(L.NextCirc(P));
NextNotSelf := P;
END;
FUNCTION Player.PrevNotSelf(L : List; X : PlayerP) : PlayerP;
VAR P : PlayerP;
BEGIN
P := PlayerP(L.PrevCirc(X));
IF P = @Self THEN P := PlayerP(L.PrevCirc(P));
PrevNotSelf := P;
END;
FUNCTION Player.FirsNotSelf(L : List) : PlayerP;
BEGIN
IF L.Firs = @Self THEN
FirsNotSelf := PlayerP(L.NextCirc(L.firs))
ELSE FirsNotSelf := PlayerP(L.Firs);
END;
(*-methods for GAME----------*)
CONSTRUCTOR game.Init(iTC : Byte);
BEGIN
Randomize;
TableColor := iTC;
players.Init; whoseturn := NIL;
{each game inits its own DECK}
END;
DESTRUCTOR game.done; BEGIN Players.done; dispose(D, done); END;
PROCEDURE game.AddPlayer(PP : PlayerP);
BEGIN
players.append(PP);
IF players.Firs = players.last THEN
WhoseTurn := PlayerP(players.Firs);
END;
PROCEDURE game.DealCards(num : word);
VAR N : byte;
P : PlayerP;
BEGIN
IF num = 0 THEN {deal 'til deck is gone}
BEGIN
P := PlayerP(players.Firs);
WHILE NOT D^.empty DO
BEGIN
P^.TakeCard(D^.FromTop);
P := PlayerP(players.NextCirc(P));
END;
END
ELSE {deal "num" cards to each player}
FOR N := 1 to num DO
BEGIN
P := PlayerP(players.Firs);
WHILE P <> NIL DO
BEGIN
P^.TakeCard(D^.FromTop);
P := PlayerP(players.next(P));
END;
END;
END;
PROCEDURE game.Display; BEGIN END;
END.